package db_utils

import (
	"database/sql"
	"dgo/goutils/utils"
	_ "dgo/goutils/utils"
	"fmt"
	"os"
	"reflect"
	"strconv"
	"time"
	_ "time"
)

type SqlValue struct {
	Value interface{}
}

func CatSqlValueList(sb *utils.BytesBuilder, spliter string, cb func(idx int, val *string) bool, lst ...SqlValue) {
	idx := 0
	for i := 0; i < len(lst); i++ {
		val := lst[i].AsString("")
		if cb != nil {
			if !cb(i, &val) {
				continue
			}
		}
		if idx > 0 {
			sb.AppendStr(spliter)
		}
		sb.AppendStr(val)
		idx++
	}
}

func GetRowFirstVal1(rows *sql.Rows) (rval SqlValue, err error) {
	if rows.Next() {
		err = rows.Scan(&rval.Value)
	}
	return
}

/*
*

	如果循环最好别用, 每次创建了cansvals
*/
func GetRowValues(rows *sql.Rows) ([]SqlValue, error) {
	flds, _ := rows.Columns()

	scanArgs := make([]interface{}, len(flds))
	values := make([]SqlValue, len(scanArgs))

	for i := range values {
		scanArgs[i] = &values[i].Value
	}

	if err := rows.Scan(scanArgs...); err != nil {
		return nil, err
	}
	return values, nil
}

func (this SqlValue) AsVar(def interface{}) interface{} {
	switch s := this.Value.(type) {
	case []byte:
		if len(s) == 1 {
			if s[0] == 0 {
				return false
			} else if s[0] == 1 {
				return true
			}
		}
		return string(s)
	case nil:
		return def
	default:
		return this.Value

	}
}

func (this SqlValue) AsString(def string) string {
	switch s := this.Value.(type) {
	case []byte:
		if len(s) == 1 {
			if s[0] == 0 {
				return "false"
			} else if s[0] == 1 {
				return "true"
			}
		}
		return string(s)
	//case time.Time:
	//	val := this.value.(time.Time)
	//	return val.Format("2006-01-02 15:04:05")
	case nil:
		return def
	default:
		return fmt.Sprintf("%v", s)
	}
}

func (this SqlValue) AsDateTime(def time.Time) time.Time {
	switch s := this.Value.(type) {
	case time.Time:
		return s
	case string:
		return utils.TryStrToTime(s, time.Local, def)
	case nil:
		return def
	default:
		fmt.Sprintf("%v", s)
		return def
	}
}

func (this SqlValue) AsBytes() []byte {
	switch s := this.Value.(type) {
	case []byte:
		return s
	default:
		str := utils.GetStrValue(s, "")
		return []byte(str)
	}
}

func (this SqlValue) AsBool(def bool) bool {
	switch s := this.Value.(type) {
	case time.Time:
		return s.IsZero()
	case []byte:
		if len(s) == 1 {
			if s[0] == 0 {
				return false
			} else if s[0] == 1 {
				return true
			}
		}
		return utils.TryStrToBool(string(s), def)
	case string:
		return utils.TryStrToBool(s, def)
	case int64:
		return s != 0 && s != -1
	case int:
		return s != 0 && s != -1
	case int32:
		return s != 0 && s != -1
	case int16:
		return s != 0 && s != -1
	case int8:
		return s != 0 && s != -1
	case uint8, uint16, uint64, uint32:
		return s != 0
	case nil:
		return def
	default:
		ty := reflect.TypeOf(this.Value)
		fmt.Fprintf(os.Stderr, "UNKONW:%s", ty.String())
		return def
	}
	return def
	//return byte(this.AsInt64(int64(def)))
}

func (this SqlValue) AsByte(def byte) byte {
	return byte(this.AsInt64(int64(def)))
}

func (this SqlValue) AsInt(def int) int {
	return int(this.AsInt64(int64(def)))
}

func (this SqlValue) AsInt32(def int32) int32 {
	return int32(this.AsInt64(int64(def)))
}

func (this SqlValue) AsInt64(def int64) int64 {
	switch s := this.Value.(type) {
	case time.Time:
		return s.UnixNano()
	case []byte:
		val, err := strconv.ParseInt(string(s), 10, 64)
		if err != nil {
			utils.Log.Err(err)
			return def
		}
		return val
	case string:
		val, err := strconv.ParseInt(s, 10, 64)
		if err != nil {
			utils.Log.Err(err)
			return def
		}
		return val
	case int64:
		return s
	case int:
		return int64(s)
	case int32:
		return int64(s)
	case int16:
		return int64(s)
	case int8:
		return int64(s)
	case nil:
		return def
	default:
		ty := reflect.TypeOf(this.Value)
		fmt.Fprintf(os.Stderr, "UNKONW:%s", ty.String())
		return def
	}
}

func (this SqlValue) AsFloat32(def float32) float32 {
	return float32(this.AsFloat64(float64(def)))
}

func (this SqlValue) AsFloat64(def float64) float64 {
	switch s := this.Value.(type) {
	case []byte:
		val, err := strconv.ParseFloat(string(s), 64)
		if err != nil {
			return def
		}
		return val
	case string:
		val, err := strconv.ParseFloat(s, 64)
		if err != nil {
			utils.Log.Err(err)
			return def
		}
		return val
	case int64:
		return float64(s)
	case int:
		return float64(s)
	case int32:
		return float64(s)
	case int16:
		return float64(s)
	case int8:
		return float64(s)
	case float32:
		return float64(s)
	case float64:
		return float64(s)
	case nil:
		return def
	default:
		ty := reflect.TypeOf(this.Value)
		fmt.Fprintf(os.Stderr, "UNKONW:%s", ty.String())
		return def
	}
}
